<template>
  <div class="graph-page">
    <div v-if="error" class="error-card">{{ error }}</div>
    <div ref="cyContainer" class="viz-container" @dblclick="emitOpenModal"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import cytoscape from 'cytoscape'

// 定义 props
const props = defineProps({
  graphData: {
    // 接收处理后的场景图数据
    type: Object,
    default: () => ({ nodes: [], edges: [] }),
  },
})

// 定义事件
const emit = defineEmits(['open-modal'])

// 定义响应式数据
const cyContainer = ref(null)
const cyInstance = ref(null)
const error = ref(null)

// 数据转换处理器（核心数据适配器）
const dataHandler = (rawData) => {
  // 修改后（添加更详细的错误信息）
  if (!rawData?.nodes || !Array.isArray(rawData.nodes)) {
    throw new Error('无效的节点数据，请检查数据格式')
  }
  if (!rawData?.edges || !Array.isArray(rawData.edges)) {
    throw new Error('无效的边数据，请检查数据格式')
  }
  return {
    // 节点数据转换逻辑
    nodes: rawData.nodes.map((n) => ({
      data: {
        ...n.properties, // 保留原始属性
        id: String(n.id), // 强制转换为字符串ID
        type: n.labels[0], // 使用第一个标签作为节点类型
        zhName: n.properties.zh_name, // 映射中文名称
        attributes: n.properties.attributes || '', // 处理空属性
      },
    })),
    // 边数据转换逻辑
    edges: rawData.edges.map((e) => ({
      data: {
        id: `e${e.id}`, // 生成唯一边ID
        source: String(e.source), // 源节点ID（强制字符串）
        target: String(e.target), // 目标节点ID（强制字符串）
        type: e.type, // 保留关系类型
        // label: '', // 设置边显示文本
        label: e.type, // 设置边显示文本
      },
    })),
  }
}

// 可视化初始化主流程
// const initVisualization = (rawData) => {
//   // 执行数据转换
//   const { nodes, edges } = dataHandler(rawData)
//   // 数据完整性校验
//   validateData(nodes, edges)

//   // 创建Cytoscape实例
//   cyInstance.value = cytoscape({
//     container: cyContainer.value, // 绑定DOM容器
//     elements: { nodes, edges }, // 注入转换后的数据
//     style: getVisualStyle(), // 应用视觉样式配置
//     layout: getLayoutConfig(), // 应用布局配置
//     minZoom: 0.2, // 最小缩放级别限制
//     maxZoom: 2, // 最大缩放级别限制
//     wheelSensitivity: 0.3, // 调整缩放速度
//   })

//   // 初始化交互功能
//   setupInteractions()
// }

// 更新可视化
const updateVisualization = (externalData) => {
  // 使用传入数据或 props 数据
  const rawData = externalData || props.graphData
  console.log('Updating with data:', rawData)
  // 执行数据转换
  const { nodes, edges } = dataHandler(rawData)
  // 数据完整性校验
  validateData(nodes, edges)

  // 如果 Cytoscape 实例未初始化，则创建
  if (!cyInstance.value) {
    cyInstance.value = cytoscape({
      container: cyContainer.value, // 绑定DOM容器
      elements: { nodes, edges }, // 注入转换后的数据
      style: getVisualStyle(), // 应用视觉样式配置
      layout: getLayoutConfig(), // 应用布局配置
      minZoom: 0.2, // 最小缩放级别限制
      maxZoom: 2, // 最大缩放级别限制
      wheelSensitivity: 0.3, // 调整缩放速度
    })
    // 初始化交互功能
    setupInteractions()
    console.log('Initialized Cytoscape')
  } else {
    // 清空现有图数据
    cyInstance.value.elements().remove()
    // 添加新数据
    cyInstance.value.add({ nodes, edges })
    // 重新布局
    cyInstance.value.layout(getLayoutConfig()).run()
    console.log('Updated Cytoscape')
  }
}

// 触发打开模态框事件
const emitOpenModal = () => {
  emit('open-modal')
}

// 监听数据变化
watch(() => props.graphData, updateVisualization, { deep: true })

// ====================== 场景节点样式配置 ======================
const getVisualStyle = () => {
  return [
    // 场景节点样式（渐变蓝）
    {
      selector: 'node[type="Scene"]',
      style: {
        label: 'data(zhName)', // 显示中文名称属性
        width: 100, // 基础尺寸：100x100像素
        height: 100,
        shape: 'ellipse', // 椭圆形状（呈现圆形效果）
        'background-color': '#4A90E2', // 基础背景色（渐变备用）
        'background-fill': 'linear-gradient', // 启用渐变填充
        'background-gradient-stop-colors': '#4A90E2 #286DA8', // 蓝-深蓝渐变
        'background-gradient-direction': 'to-bottom', // 垂直向下渐变
        color: '#FFFFFF', // 文字颜色为纯白
        'font-size': 16, // 字号较大突出重要性
        'font-weight': '600', // 加粗字体提高可读性
        'text-outline-color': '#000', // 文字描边色与渐变协调  #000
        'text-outline-width': 2, // 2像素描边抗背景干扰
        'text-valign': 'center', // 垂直居中显示
        'text-halign': 'center', // 水平居中显示
        'border-width': 2, // 2像素白色边框
        'border-color': '#FFFFFF', // 边框增强节点层次感
      },
    },
    //  ====================== 物体节点样式配置 ======================
    {
      selector: 'node[type="Object"]',
      style: {
        label: 'data(zhName)', // 显示节点zhName属性的中文名称
        width: 80, // 节点直径80像素（圆形实际显示为直径80px）
        height: 80, // 保持与width相同值实现正圆形
        shape: 'ellipse', // 强制显示为椭圆（width=height时即为正圆）
        'background-color': '#50C9BA', // 基础背景色（当渐变不可用时显示）
        'background-fill': 'linear-gradient', // 启用线性渐变填充
        'background-gradient-stop-colors': '#50C9BA #50C9BA', // 从浅青绿到深青绿的渐变
        'background-gradient-direction': 'to-bottom', // 垂直向下渐变
        color: '#FFFFFF', // 文字颜色纯白
        'font-size': 14, // 字号14px
        'text-outline-color': '#000', // 文字描边色（与渐变深色区呼应）#000
        'text-outline-width': 1.5, // 1.5像素描边（抗背景干扰）
        'text-valign': 'center', // 垂直居中（基于节点高度）
        'text-halign': 'center', // 水平居中（基于节点宽度）
        'border-width': 2, // 2像素边框宽度
        'border-color': 'rgba(255,255,255,0.8)', // 半透明白色边框（增强立体感）
      },
    },
    // ====================== 边关系样式配置 ======================
    {
      selector: 'edge',
      style: {
        label: 'data(label)', // 显示关系类型标签
        width: 3, // 边宽3像素
        'line-style': 'dashed', // 虚线风格增加设计感
        'line-dash-pattern': [6, 3], // 6像素实线+3像素间隔的虚线模式
        'line-color': '#7C8B9E', // 灰蓝色边线（中性色调）
        'target-arrow-color': '#7C8B9E', // 箭头颜色与边线一致
        'target-arrow-shape': 'triangle', // 三角形箭头指示方向
        'curve-style': 'bezier', // 贝塞尔曲线优化交叉显示
        'font-size': 12, // 关系标签字号
        color: '#4A5568', // 深灰色标签文字
        'text-outline-color': '#FFF', // 白色文字描边
        'text-outline-width': 2, // 2像素描边抗背景干扰
      },
    },
  ]
}

// 布局配置
const getLayoutConfig = () => {
  return {
    // 布局算法类型：使用力导向布局(cose算法)，适合复杂网络关系可视化
    name: 'cose',

    // 动画模式：在布局完成后执行动画（'end'表示不实时更新动画，优化性能）
    animate: 'end',

    // 动画时长：布局调整动画持续1000ms（1秒）
    animationDuration: 0,

    // 自适应容器：自动缩放和平移图形使其完整显示在容器内
    fit: true,

    // 边距设置：图形与容器边缘保持50px间距
    padding: 50,

    // 包含标签尺寸：计算布局时考虑节点标签所占空间（防止标签重叠）
    nodeDimensionsIncludeLabels: true,

    // 重力系数：0.25的向心引力（值越大节点越聚向中心）
    gravity: 0.25,

    // 组件间距：不同连通组件之间保持100px间距（适用于多子图情况）
    componentSpacing: 100,
  }
}

// 交互设置
const setupInteractions = () => {
  // 节点悬停效果
  cyInstance.value.on('mouseover', 'node', (e) => {
    const node = e.target
    node.animate(
      {
        style: {
          width: node.data('type') === 'Scene' ? 120 : 100,
          height: node.data('type') === 'Scene' ? 120 : 100,
          'border-width': 4,
        },
      },
      { duration: 200 },
    )
  })

  cyInstance.value.on('mouseout', 'node', (e) => {
    const node = e.target
    node.animate(
      {
        style: {
          width: node.data('type') === 'Scene' ? 100 : 80,
          height: node.data('type') === 'Scene' ? 100 : 80,
          'border-width': 2,
        },
      },
      { duration: 200 },
    )
  })

  // 点击显示详细信息
  cyInstance.value.on('tap', 'node', (e) => {
    const node = e.target
    const pos = node.renderedPosition()
    showDetailCard(node.data(), pos)
  })
}

// 显示详情卡片
const showDetailCard = (data, position) => {
  const card = document.createElement('div')
  card.className = 'detail-card'
  card.innerHTML = `
      <h3>${data.zhName}</h3>
      <div class="meta-info">
        <span class="type-tag">${data.type}</span>
        ${data.attributes ? `<p class="attributes">${data.attributes}</p>` : ''}
      </div>
    `
  Object.assign(card.style, {
    left: `${position.x + 20}px`,
    top: `${position.y}px`,
    transform: 'translateY(-50%)',
  })

  cyContainer.value.appendChild(card)
}

// 数据验证
const validateData = (nodes, edges) => {
  const nodeIds = new Set(nodes.map((n) => n.data.id))
  edges.forEach((e) => {
    if (!nodeIds.has(e.data.source)) throw `无效源节点: ${e.data.source}`
    if (!nodeIds.has(e.data.target)) throw `无效目标节点: ${e.data.target}`
  })
}

const handleError = (err) => {
  console.error('可视化错误:', err)
  error.value = err.message || err
}

// 组件挂载时自动执行数据加载和可视化初始化
onMounted(async () => {
  updateVisualization()
})

// 组件销毁前清理Cytoscape实例，防止内存泄漏
onBeforeUnmount(() => {
  cyInstance.value?.destroy()
})
</script>

<style scoped>
.graph-page {
  /* padding: 2rem; */
  /* height: 100vh; */
  background: #fcf7f7;
  width: 100%;
  height: 100%;
}

.viz-container {
  /* height: calc(100vh - 120px); */
  border-radius: 8px;
  /* box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); */
  background: white;
  position: relative;
  width: 100%;
  /* height: 830px; */
  height: 100%;
  /* border: 1px solid #ccc; */
  cursor: pointer; /* 鼠标悬停时显示手型 */
}

.error-card {
  padding: 1rem;
  background: #fed7d7;
  color: #9b2c2c;
  border-radius: 8px;
  margin-bottom: 1rem;
}

/* 详情卡片样式 */
.detail-card {
  position: absolute;
  background: white;
  padding: 1.2rem;
  border-radius: 8px;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
  border: 1px solid #e2e8f0;
  max-width: 300px;
  z-index: 1000;
}

.detail-card h3 {
  color: #2d3748;
  margin: 0 0 0.8rem;
  font-size: 1.1rem;
}

.type-tag {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  background: #4a90e2;
  color: white;
  border-radius: 999px;
  font-size: 0.8rem;
}

.attributes {
  color: #718096;
  margin: 0.8rem 0 0;
  font-size: 0.9rem;
  line-height: 1.4;
}
</style>
